#include <iostream>
#include <cmath>

#include "visitor.h"

// #define TEST

void Visitor::setValue(antlr4::tree::ParseTree *node, double value){
    valueTree.put(node, value);
}

double Visitor::getValue(antlr4::tree::ParseTree *node){
    return valueTree.get(node);
}

antlrcpp::Any Visitor::visitStat(calculatorParser::StatContext *context) {
    #ifdef TEST
    std::cout << "start visit stat" << std::endl;
    #endif
    visit(context->exp());  // 递归遍历子节点
    std::cout << getValue(context->exp()) << std::endl;  // 打印输出四则运算的结果值
    #ifdef TEST
    std::cout << "end visit stat" << std::endl;
    #endif
    return antlrcpp::Any(nullptr);
}

antlrcpp::Any Visitor::visitExpUnary(calculatorParser::ExpUnaryContext *context) {
    #ifdef TEST
    std::cout << "start visit exp unary" << std::endl;
    #endif
    visit(context->exp());  // 递归遍历子节点
    if (context->opUnary()->getText() == "-"){  // 根据此分析树节点将值转化为正或负
        setValue(context, -getValue(context->exp()));  // 通过getValue获取子节点的值，然后setValue将计算结果放到字典里
    }
    if (context->opUnary()->getText() == "+"){
        setValue(context, getValue(context->exp()));
    }
    
    #ifdef TEST
    std::cout << "end visit exp unary" << std::endl;
    #endif
    return antlrcpp::Any(nullptr);
}

antlrcpp::Any Visitor::visitExpParent(calculatorParser::ExpParentContext *context) {
    #ifdef TEST
    std::cout << "start visit exp parent" << std::endl;
    #endif
    visit(context->exp());
    setValue(context, getValue(context->exp()));
    #ifdef TEST
    std::cout << "end visit exp parent" << std::endl;
    #endif
    return antlrcpp::Any(nullptr);
}

antlrcpp::Any Visitor::visitExpNumber(calculatorParser::ExpNumberContext *context) {
    #ifdef TEST
    std::cout << "start visit exp number" << std::endl;
    #endif
    visit(context->number());
    setValue(context, getValue(context->number()));
    #ifdef TEST
    std::cout << "end visit exp number" << std::endl;
    #endif
    return antlrcpp::Any(nullptr);
}

antlrcpp::Any Visitor::visitExpPow(calculatorParser::ExpPowContext *context) {
    #ifdef TEST
    std::cout << "start visit exp pow" << std::endl;
    #endif
    visit(context->exp(0));
    visit(context->exp(1));
    setValue(context, pow(getValue(context->exp(0)), getValue(context->exp(1))));
    #ifdef TEST
    std::cout << "end visit exp pow" << std::endl;
    #endif
    return antlrcpp::Any(nullptr);
}

antlrcpp::Any Visitor::visitExpMulDiv(calculatorParser::ExpMulDivContext *context) {
    #ifdef TEST
    std::cout << "start visit exp muldivmod" << std::endl;
    #endif
    visit(context->exp(0));  // 递归遍历子节点；分析树节点的子节点定义可以通过看ANTLR4生成的分析树头文件里的定义来得到。
    visit(context->exp(1));  // 递归遍历子节点
    if (context->opMulDiv()->getText() == "*"){
        setValue(context, getValue(context->exp(0)) * getValue(context->exp(1)));
    }
    if (context->opMulDiv()->getText() == "/"){
        setValue(context, getValue(context->exp(0)) / getValue(context->exp(1)));
    }
    #ifdef TEST
    std::cout << "end visit exp muldivmod" << std::endl;
    #endif
    return antlrcpp::Any(nullptr);
}

antlrcpp::Any Visitor::visitExpAddSub(calculatorParser::ExpAddSubContext *context) {
    #ifdef TEST
    std::cout << "start visit exp addsub" << std::endl;
    #endif
    visit(context->exp(0));
    visit(context->exp(1));
    if (context->opAddSub()->getText() == "+"){
        setValue(context, getValue(context->exp(0)) + getValue(context->exp(1)));
    }
    if (context->opAddSub()->getText() == "-"){
        setValue(context, getValue(context->exp(0)) - getValue(context->exp(1)));
    }
    #ifdef TEST
    std::cout << "end visit exp addsub" << std::endl;
    #endif
    return antlrcpp::Any(nullptr);
}

antlrcpp::Any Visitor::visitNumber(calculatorParser::NumberContext *context) {
    #ifdef TEST
    std::cout << "start visit number" << std::endl;
    #endif
    if (context->Int()!=nullptr) {
        setValue(context, std::stoi(context->Int()->getText()));
    }
    if (context->Float()!=nullptr) {
        setValue(context, std::stod(context->Float()->getText()));
    }
    #ifdef TEST
    std::cout << "end visit number" << std::endl;
    #endif
    return antlrcpp::Any(nullptr);
}

antlrcpp::Any Visitor::visitOpUnary(calculatorParser::OpUnaryContext *context) {
    return antlrcpp::Any(nullptr);
}

antlrcpp::Any Visitor::visitOpMulDiv(calculatorParser::OpMulDivContext *context) {
    return antlrcpp::Any(nullptr);
}

antlrcpp::Any Visitor::visitOpAddSub(calculatorParser::OpAddSubContext *context) {
    return antlrcpp::Any(nullptr);
}